﻿const camera = (function () {
    let g_stream, ctx, g_width, g_height, video, canvas;

    async function getDevices() {
        const mediaDevices = await navigator.mediaDevices.enumerateDevices();
        const videoDevices = mediaDevices.filter(device => device.kind === 'videoinput' && device.label);
        return videoDevices;
    }

    function createCanvas(container) {
        const id = '#cameraCanvas';
        const canvas = document.querySelector(id);

        let { clientWidth: width, clientHeight: height } = container;

        if (!canvas) {
            const c = document.createElement('canvas');
            c.id = id;
            c.style.display = 'none';
            c.width = width;
            c.height = height;
            container.appendChild(c);
            return c;
        } else {
            return canvas;
        }
    }

    function createVideo(container) {
        const id = '#cameraVideo';
        const video = document.querySelector(id);

        let { clientWidth: width, clientHeight: height } = container;

        if (!video) {
            const v = document.createElement('video');
            v.id = id;
            v.width = width;
            v.height = height;
            container.appendChild(v);
            return v;
        } else {
            return video;
        }
    }

    function open(deviceId, container) {
        g_stream?.getTracks().forEach(track => {
            track.stop();
            g_stream = null;
        });

        let { clientWidth: width, clientHeight: height } = video;

        g_width = width;
        g_height = height;

        const constraints = {
            video: {
                deviceId: { exact: deviceId },
                width,
                height
            },
            audio: false
        };

        return new Promise((resolve, reject) => {
            navigator.mediaDevices.getUserMedia(constraints)
                .then(stream => {
                    video.srcObject = g_stream = stream;
                    video.play();
                    resolve(stream);
                })
                .catch(err => {
                    console.error('访问摄像头失败', err);
                    reject(err);
                });
        });
    }

    function take() {
        ctx.drawImage(video, 0, 0, g_width, g_height);

        return new Promise((resolve, reject) => {
            canvas.toBlob((blob) => {
                const reader = new FileReader();
                reader.onloadend = () => {
                    resolve({
                        blob,
                        base64: reader.result,
                        url: URL.createObjectURL(blob),
                        date: Date.now()
                    });
                };
                reader.readAsDataURL(blob);
            }, 'image/jpeg');
        });
    }
    //默认打开摄像头
    async function OpenVideo(cameraName, container, successCallback, failedCallback) {
        container.innerHTML = "";
        canvas = createCanvas(container);
        video = createVideo(container);
        ctx = canvas.getContext('2d');

        try {
            const devices = await getDevices();
            await Promise.all(devices.map(async device => {
                if (device.kind === 'videoinput' && device.label && device.deviceId) {
                    if (device.label.indexOf(cameraName) !== -1) {
                        const resp = await open(device.deviceId, container);
                        await successCallback?.(resp);
                    }
                } else {
                    throw '没有找到有效的设备';
                }
            }));
        } catch (error) {
            console.error(error);
            failedCallback?.();
        }
    }
    async function init() {
        await navigator.mediaDevices.getUserMedia({ video: true });
    }


    // 停止按钮点击事件
    function close(params) {
        if (g_stream) {
            g_stream.getTracks().forEach(track => {
                track.stop();
            });
            g_video.srcObject = null;
        }
    }

    return { OpenVideo, getDevices, init, take, close };
})();